Diffusion en direct avec l'API Video de Vonage

L'API Video de Vonage vous permet de créer à peu près n'importe quelle expérience vidéo. L'un des cas d'utilisation les plus courants pour les développeurs est le besoin de situations où une ou quelques personnes diffusent à un public plus large qui ne fait qu'écouter, comme les participants qui regardent la diffusion en direct d'une conférence.

Dans ce tutoriel

L'API Video de Vonage vous permet d'organiser rapidement une salle pour permettre à une seule personne de diffuser, et à d'autres personnes de se joindre et de regarder. Nous verrons comment faire fonctionner une démo avec nos démos existantes afin que vous n'ayez pas à écrire de code, mais nous expliquerons également ce que le code fait en arrière-plan.

  1. Voir la démo - Découvrez la démo sans écrire de code
  2. Fonctionnement de la démo - Côté client - Ce que fait le code côté client
  3. Fonctionnement de la démo - Côté serveur - Ce que fait le code côté serveur

Conditions préalables

Pour compléter le tutoriel, vous avez besoin de :

Voir la démo

Si vous souhaitez tester la démo avant d'écrire le moindre code, nous disposons d'un exemple de serveur web et de code JavaScript pour tester ce à quoi ressemble un appel vidéo de base. Tout le code est open source et accessible au public, vous pouvez donc essayer la démo et utiliser le code pour faire vos propres modifications.

Lancer le serveur Node.js

La démo vidéo nécessite un serveur dorsal pour gérer des tâches telles que la création de jetons clients pour l'autorisation et la gestion générale de la session. Bien que vous puissiez construire ceci dans le langage de votre choix, nous avons un serveur pré-construit que vous pouvez utiliser pour commencer à l'adresse suivante Serveur d'apprentissage vidéo de Vonage (Node.js) sur Code Hub. De la Documentation pour les développeursCliquez sur "Code Hub" dans la barre de navigation supérieure, puis faites défiler vers le bas et trouvez la carte "Vonage Video Learning Server (Node.js)". Cliquez dessus pour l'ouvrir.

Vous obtiendrez une description de ce que fait ce projet. Pour l'instant, cliquons sur "Get code" afin de pouvoir le charger dans l'éditeur en ligne Code Hub. Cliquez sur "Créer un nouvel environnement de développement". Nommez l'espace de travail "Vonage Video Demo" car nous pouvons utiliser ce backend pour plusieurs démonstrations. Cette démo nécessite l'attribution d'un numéro, car le serveur d'apprentissage prend en charge les appels téléphoniques via SIP. Nous ne l'utiliserons pas dans cette démonstration, mais vous pouvez cliquer sur "Attribuer un numéro" pour attribuer un numéro existant que vous avez obtenu auprès de Vonage, ou en acheter un nouveau que vous utiliserez pour des démonstrations ultérieures.

Creating a new workspace

Code Hub créera automatiquement une application pour vous, y compris la mise en place des clés publiques et privées que notre application utilisera. Une fois l'espace de travail créé, vous serez dirigé vers l'éditeur de code, qui est une version en ligne de Visual Studio Code. N'hésitez pas à suivre les parties ultérieures de cette démo pour voir le code, et vous pouvez modifier ce code si nécessaire pour vos propres projets.

Code editor

Pour exécuter l'application, cliquez sur "View" en haut de l'éditeur, puis sur "Terminal". Cela ouvrira une ligne de commande dans laquelle nous pourrons exécuter des commandes. Tout ce que nous avons à faire est de taper vcr deploy et le code sera déployé. Cela prendra quelques instants, car le code est emballé et exécuté sur les serveurs de Vonage Code Hub. Nous voudrons prendre note de "l'adresse de l'hôte de l'instance" qu'il produit vers la fin.

Deploying the project

Si tout fonctionne correctement, vous devriez pouvoir visiter l'adresse de l'hôte de l'instance et être accueilli par la page suivante :

Learning Server homepage

Tester la partie frontale

Le serveur dorsal fonctionne directement avec toutes nos démonstrations préconstruites, y compris cette démo en tête-à-tête. Rendez-vous sur le site de https://github.com/Vonage-Community/video-api-web-samples/tree/main/Live-Broadcastqui est le code source de la partie frontale de cette démo. Cet exemple permet à deux utilisateurs ayant l'URL de rejoindre la démo.

La façon la plus simple d'exécuter cette démo est de cliquer sur le bouton "Open in Stackblitz" dans le README.

Basic Video Chat README

Ceci ouvrira le projet dans Stackblitz. Comme pour le serveur backend, vous pouvez parcourir le code et le modifier ici si vous le souhaitez. Pour cette démo, tout ce que nous avons besoin de faire est d'ouvrir le fichier js/config.js et ajoutez l'URL de l'instance de Code Hub dans le fichier SAMPLE_SERVER_BASE_URL variable :

Stackblitz Demo Config

Une fois que vous avez enregistré le fichier, vous pouvez rafraîchir la vue de démonstration sur le côté droit de Stackblitz. Cet exemple est divisé en plusieurs parties, dont une vue de l'hôte et deux façons différentes de visionner la vidéo elle-même. Nous nous concentrerons sur la diffusion non-RTMP.

Comment fonctionne la démo

Configurer une application Vonage

Pour que notre application vidéo fonctionne, il faut que notre client et notre serveur puissent communiquer avec les serveurs de Vonage. Code Hub configure cela pour nous, mais si vous exécutez le code localement ou si vous voulez savoir ce que cela implique, une application Video est configurée comme n'importe quelle autre API. Nous devons mettre en place une Applications Vonage pour héberger toute la configuration de notre application, ainsi que pour aider à générer les éléments nécessaires à l'authentification.

Rendez-vous sur votre Tableau de bord des clients de Vonage et se connecter. Une fois que vous êtes connecté :

  1. Cliquez sur "Applications" sous "Construire".
  2. Cliquez sur "Créer une nouvelle application".
  3. Donnez un nom à l'application, par exemple "Démonstration vidéo de base".
  4. Cliquez sur "Generate public and private key", ce qui vous permettra de télécharger un fichier nommé private.key. Gardez une trace de ce fichier pour plus tard.
  5. Faites défiler vers le bas et cliquez sur "Vidéo". Nous laisserons ces valeurs vides pour l'instant.
  6. Cliquez sur "Générer une nouvelle application" pour créer l'application.

Une fois l'application créée, notez l'identifiant de l'application. Si vous exécutez le code localement, nous en aurons besoin pour configurer le backend. Si vous utilisez Code Hub, le code du serveur a déjà accès à l'identifiant de l'application et à la clé privée.

Le côté client

La partie client de la démo se compose de deux parties différentes : quelques éléments HTML pour placer les flux vidéo, puis du JavaScript pour récupérer les informations de connexion et communiquer avec les serveurs vidéo de Vonage.

Comme il s'agit d'une démonstration par navigateur, nous utilisons le SDK JavaScript situé à l'adresse suivante https://unpkg.com/@vonage/client-sdk-video@latest/dist/js/opentok.jset l'inclure dans une balise de script dans notre HTML en index.html.

L'hôte

Pour la vue de l'hôte, nous n'avons besoin que de la caméra de l'hôte, ainsi que d'une interface utilisateur pour contrôler différentes options comme le démarrage de la diffusion, l'activation de la faible latence et les mises à jour d'état. Pour visualiser votre propre caméra, nous créons une interface <div> pour héberger l'élément vidéo :

// host.html
<div>
    <h2 class="font-black text-2xl">Your Camera</h2>
    <div class="h-80 w-80" id="host"></div>
</div>

Le reste de la page de l'hôte est constitué de boutons et de configurations pour la diffusion en direct elle-même. Nous ne nous occuperons pas de toutes les options, mais plutôt des contrôles de diffusion. Il s'agit de simples boutons que nous allons câbler pour appeler l'application serveur afin de démarrer et d'arrêter les flux de diffusion.

// host.html
<div><h2 class="font-black text-2xl">Broadcast Controls</h2></div>

<div>
    <button x-show="broadcastStatus == 'stopped'" x-on:click="broadcastStatus = 'started'" id="btn-start" class="bg-blue-500 bold text-white p-4 rounded">Start Broadcast</button>
    <button x-show="broadcastStatus == 'started'" x-on:click="broadcastStatus = 'stopped'"  id="btn-end" class="bg-red-500 bold text-white p-4 rounded">Stop Broadcast</button>
</div>

Notre connexion en JavaScript est minimale par rapport à d'autres configurations où plusieurs personnes s'engagent ensemble. Normalement, nous devrions nous connecter à la session et publier immédiatement nos flux vidéo et audio, mais comme nous contrôlons le moment où la diffusion commence et s'arrête, nous le ferons en deux étapes. Tout d'abord, nous nous connectons à la session comme d'habitude :

// js/host.js

document.addEventListener('DOMContentLoaded', async () => {
    const credentials = await getCredentials('host');
    const session = OT.initSession(
        credentials.applicationId,
        credentials.sessionId,
        {
            connectEventsSuppressed: true
        }
    );

    session.connect(credentials.token, (error) => {
        if (error) {
            console.error(error);
            return;
        }

        let publisher = initPublisher();
        // ...

Une fois que nous nous sommes connectés au flux, nous ajoutons un écouteur d'événements sur le fichier btn-start afin de publier et de démarrer le flux lorsque l'utilisateur appuie sur ce bouton. Le démarrage (et la fin) de la diffusion est géré par les SDK côté serveur, nous faisons donc une demande à notre serveur dorsal pour démarrer la diffusion.

// js/host.js

document.getElementById('btn-start').addEventListener('click', async (el, event) => {
    const rtmp = [];
    if (document.getElementById('rtmpAddress').value) {
        rtmp.push({
            serverUrl: document.getElementById('rtmpAddress').value,
            streamName: document.getElementById('rtmpKey').value,
        });
    }
    broadcast = await fetch(`${SAMPLE_SERVER_BASE_URL}/broadcast/session/start`, {
        method: "POST",
        body: JSON.stringify({
            rtmp,
            lowLatency: document.getElementById('lowLatency').checked,
            dvr: document.getElementById('dvr').checked,
            sessionId: session.id,
            streamMode: "auto"
        }),
        headers: {
            "Content-type": "application/json"
        }
    })
        .then(res => {
            // Once the broadcast starts we finally publish the host
            session.publish(publisher);
            shouldCheckBroadcast = true;
            setTimeout(checkBroadcast, 5000);
            return res.json()
        })
        .catch(error => console.error(error));
});

À ce stade, notre hôte publie maintenant par le biais de la diffusion elle-même, ainsi que toute autre personne qui se connecte. La démo dont nous disposons prend en charge les invités, de sorte que lorsque des invités sont conviés aux réunions, leurs flux sont automatiquement ajoutés à la diffusion par l'API Video de Vonage.

L'arrêt de la diffusion est effectué par l'application serveur, de sorte qu'un appel rapide à cette route sur notre serveur dorsal arrêtera la diffusion elle-même. Nous attachons un écouteur d'événements à la route btn-stop à déclencher lorsqu'on clique dessus.

// js/host.js

document.getElementById('btn-end').addEventListener('click', async (el, event) => {
    broadcast = await fetch(`${SAMPLE_SERVER_BASE_URL}/broadcast/session/stop`, {
        method: "POST",
        body: JSON.stringify({
            sessionId: session.id
        }),
        headers: {
            "Content-type": "application/json"
        }
    })
        .then(res => {
            session.unpublish(publisher);
            shouldCheckBroadcast = false;
            publisher = initPublisher();
            return res.json()
        })
        .catch(error => console.error(error));
});

Le téléspectateur - Stream Broadcasting

Pour une visionneuse, nous avons seulement besoin d'un endroit pour afficher le flux vidéo de l'hôte. Comme les spectateurs ne publieront pas leurs propres flux, nous aurons beaucoup moins de code frontal à travailler avec eux. Nous allons créer un <div> pour contenir le flux de l'hôte.

// view.html

<div class="grid grid-cols-1 container mx-auto pt-4">
    <h2 class="font-black text-2xl mx-auto">Host Camera</h2>
    <div class="w-1/2 h-96 mx-auto" id="host"></div>
</div>

Étant donné qu'un spectateur ne publie jamais ses propres flux, notre JavaScript se connecte simplement au flux et attend que des flux soient créés par la diffusion :

// js/view.js

const credentials = await getCredentials('viewer');
const session = OT.initSession(
    credentials.applicationId,
    credentials.sessionId,
    {
        connectEventsSuppressed: true
    }
);

session.connect(credentials.token, (error) => {
    if (error) {
        console.log(error);
        return;
    }

    session.on('streamCreated', (event) => {
        session.subscribe(event.stream, 'host', {
            insertMode: 'append',
            width: '100%',
            height: '100%',
        })
    });
});

La visionneuse - HLS

L'exécution de la HLS ne nécessite que l'ajout d'un <video> au lieu d'utiliser un élément <div>. Si vous voulez utiliser HLS à la place, nous faisons un <video> auquel nous attacherons une source ultérieurement. Notez que vous aurez besoin de JavaScript supplémentaire pour la plupart des navigateurs, nous inclurons donc également la bibliothèque JavaScript HLS, disponible sur NPM :

// hls.html

<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>

<div class="grid grid-cols-1 container mx-auto pt-4">
    <h2 class="font-black text-2xl mx-auto">HLS Stream</h2>
    <div id="host">
        <video class="w-1/2 mx-auto" id="video" autoplay controls></video>
    </div>
</div>

Dans notre démo, l'utilisateur obtient une URL de l'hôte qui contient l'URL de la diffusion comme paramètre de requête. Nous l'utiliserons pour attacher ce flux au lecteur vidéo. Nous effectuerons également quelques vérifications de base pour nous assurer que le HLS est pris en charge, car tous les navigateurs ne prennent pas en charge le HLS d'emblée.

const video = document.getElementById('video');
const videoSource = new URLSearchParams(window.location.search).get('url');

if (!videoSource) {
    alert('No HLS URL was passed. No video will be displayed');
    return;
}

if (Hls.isSupported()) {
    const hls = new Hls();
    hls.on(Hls.Events.MEDIA_ATTACHED, () => {
        video.muted = true;
        video.play();
    });

    hls.loadSource(videoSource);
    hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = videoSource;
} else {
    alert('Browser does not seem to have HLS capabilities. No video will be displayed');
    return;
}
});

Le côté serveur

La partie serveur de toute application Vonage Video est utilisée pour gérer la création de sessions, la génération de jetons d'authentification et les tâches administratives telles que le démarrage et l'arrêt des archives. Pour cette démonstration, tout ce qui nous préoccupe est de créer des sessions et des jetons pour que les utilisateurs puissent rejoindre la salle. Bien que l'API elle-même soit une API REST et qu'elle puisse être appelée comme vous le souhaitez, nous vous encourageons à utiliser l'API SDK Vonage Node qui gère l'authentification et les appels HTTP pour vous. Vous pouvez l'installer dans votre propre application avec :

npm install -s @vonage/server-sdk

Le code de démonstration l'a déjà préinstallé. Si vous exécutez le code localement, vous devrez exécuter :

npm install

pour télécharger toutes les dépendances, puis copier .envcopy dans un nouveau fichier nommé .env. Vous devrez remplir les informations demandées dans le formulaire suivant .env comme l'ID de l'Application, l'emplacement de la clé privée sur le disque, ainsi que la clé et le secret de l'API de Vonage.

L'hôte

Nous donnerons à l'hôte un moderator Ainsi, lorsque le front-end demande des informations d'identification, nous créons la session avec le rôle approprié. Sinon, il n'y a pratiquement aucune différence entre la session d'un animateur de diffusion en direct et celle d'un utilisateur de vidéo normal avec le rôle moderator rôle.

// routes/index.js

router.get('/broadcast/:name/host', async function (req, res) {
  const broadcastName = req.params.name + '-broadcast';
  await createSession(res, broadcastName, { initialLayoutClassList: ['full', 'focus'] }, 'moderator');
});

Pour plus d'informations sur la création de jetons, consultez notre rubrique Cas d'utilisation de la vidéo en tête-à-tête qui détaille la manière dont les sessions peuvent être créées.

Lorsque l'utilisateur souhaite lancer la diffusion, nous utilisons le SDK du serveur pour appeler la fonction vonage.video.startBroadcast() qui transformera les flux publiés en session de diffusion. Nous renvoyons ensuite ces données au client afin qu'il dispose de toutes les informations nécessaires pour rechercher la diffusion et la contrôler ultérieurement.

// routes/index.js

router.post('/broadcast/:room/start', async (req, res) => {
  const { rtmp, lowLatency, fhd, dvr, sessionId, streamMode } = req.body;
  // Kill any existing broadcasts we have, to be safe
  vonage.video.searchBroadcasts({sessionId})
    .then(list => {
      list.items.map(async (broadcast) => {
        vonage.video.stopBroadcast(broadcast.id)
      })
    })

  vonage.video.startBroadcast(sessionId, {outputs: {rtmp, hls: {lowLatency, dvr}}, streamMode})
    .then(data => {
      broadcastsToSessionIdDictionary[sessionId] = data;
      res.send(data)
    })
    .catch(error => {
      console.error(error);
      res.status(500).send(error)
    })
})

La fin de la diffusion est en grande partie la même - nous appelons le SDK du serveur vonage.video.stopBroadcast() pour mettre fin à la diffusion.

// routes/index.js

router.post('/broadcast/:room/stop', async (req, res) => {
  const { sessionId } = req.body
  if (broadcastsToSessionIdDictionary[sessionId]) {
    vonage.video.stopBroadcast(broadcastsToSessionIdDictionary[sessionId].id)
      .then(data => {
        delete broadcastsToSessionIdDictionary[sessionId]
        res.send(data)
      })
      .catch(err => {
        console.error(err)
        res.status(500).send(err)
      })
  }
})

Le téléspectateur - Stream Broadcasting

Dans le cas d'une diffusion, il suffit de donner au spectateur le type de jeton de connexion approprié. Tout le reste est géré dans le navigateur par le code côté client.

router.get('/broadcast/:name/viewer', async function (req, res) {
  const broadcastName = req.params.name + '-broadcast';
  await createSession(res, broadcastName, { initialLayoutClassList: ['full', 'focus'] }, 'subscriber');
});

La visionneuse - HLS

Les téléspectateurs qui regardent via HLS n'ont pas besoin d'informations de connexion particulières, car tout passe par le lecteur vidéo et l'URL de diffusion. Il n'est donc pas nécessaire d'utiliser un code côté serveur pour générer des jetons. Si vous souhaitez empêcher les téléspectateurs de regarder une émission, vous devrez l'intégrer dans votre application.

Conclusion

Dans ce tutoriel, vous avez vu ce qui entre dans le serveur dorsal pour la diffusion basée sur le flux et la diffusion basée sur HLS, comment créer un client Web pour que les utilisateurs puissent regarder les diffusions, ainsi qu'un aperçu de la facilité d'utilisation du Vonage Code Hub et de Stack Blitz pour tester rapidement des échantillons.

Pour en savoir plus